use bigdecimal::BigDecimal;
use std::str::FromStr;

#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum TokenType {
    Number,
    Plus,
    Minus,
    Multiply,
    Divide,
    LeftParen,
    RightParen,
}

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Token {
    pub word: String,
    pub token_type: TokenType,
    pub level: u8,
}

// 中缀转后缀表达式
pub fn build_postfix_expression(token_list: Vec<Token>) -> Vec<Token> {
    let mut postfix_token_list: Vec<Token> = Vec::<Token>::new();
    let mut operator_stack: Vec<Token> = Vec::new();
    for token in token_list {
        match &token.token_type {
            TokenType::Number => {
                postfix_token_list.push(token);
            }
            TokenType::LeftParen => {
                operator_stack.push(token);
            }
            TokenType::RightParen => {
                while let Some(op) = operator_stack.pop() {
                    if op.token_type == TokenType::LeftParen {
                        break;
                    }
                    postfix_token_list.push(op);
                }
            }
            _ => {
                // 操作符优先级比较
                while let Some(top_op) = operator_stack.last() {
                    if top_op.level >= token.level && top_op.token_type != TokenType::LeftParen {
                        postfix_token_list.push(operator_stack.pop().unwrap());
                    } else {
                        break;
                    }
                }
                operator_stack.push(token);
            }
        }
    }

    while let Some(op) = operator_stack.pop() {
        postfix_token_list.push(op);
    }

    postfix_token_list
}

// 判断是否为数字
fn is_number(input: char) -> bool {
    input.is_ascii_digit() || input == '.'
}

// 添加token到集合
fn add_value(token_list:&mut Vec<Token>, word: String, token_type: TokenType, level: u8) {
    let tk = Token {
        word: word,
        token_type,
        level,
    };
    token_list.push(tk);
} 

// 简单的词法分析器
pub fn tokenize(input: &str) -> Vec<Token> {
    let trim_input = input.trim();

    let mut token_list: Vec<Token> = Vec::new();
    let mut current_number = String::new();
    let chars: Vec<char> = trim_input.chars().collect();
    
    for i in 0..chars.len() {
        let c = chars[i];
        if c.is_whitespace() {
            continue;
        }

        if is_number(c) || (current_number.len() == 0 && (c == '-' || c == '+') && is_number(chars[i + 1])) {
            //println!("The `{}` is number !", c);
            // 是数字，拼接数字
            current_number.push(c);
        } else {
            // 不是数字，提交数字
            if !current_number.is_empty() {
                add_value(&mut token_list, current_number.clone(), TokenType::Number, 0);
                current_number.clear();
            }

            // 符号入栈
            let token_type: TokenType = match c {
                '+' => TokenType::Plus,
                '-' => TokenType::Minus,
                '*' => TokenType::Multiply,
                '/' => TokenType::Divide,
                '(' => TokenType::LeftParen,
                ')' => TokenType::RightParen,
                _ => panic!("Unknown character: {}", c),
            };
            let level: u8 = match c {
                '+' => 0,
                '-' => 0,
                '*' => 1,
                '/' => 1,
                '(' => 0,
                ')' => 2,
                _ => panic!("Unknown character: {}", c),
            };
            let mut new_str = String::new();
            new_str.push(c);
            //println!("The `{}` is not number !", new_str);
            add_value(&mut token_list, new_str.clone(), token_type.clone(), level);
        }
    }

    // 处理最后一个数字
    if !current_number.is_empty() {
        let tk = Token {
            word: current_number.clone(),
            token_type: TokenType::Number,
            level: 0,
        };
        token_list.push(tk.clone());
        //println!("{:?}", tk);
        current_number.clear();
    }

    token_list
}


// 计算中缀表达式
pub fn calc_postfix(list: Vec<Token>) -> String {
    let mut stack_list: Vec<Token> = Vec::<Token>::new();
    for i in 0..list.len() {
        let tk_item: Token = list[i].clone();
        if tk_item.token_type == TokenType::Number {
            stack_list.push(tk_item.clone());
        } else {
            let tk_word_1 = stack_list.pop().unwrap().word;
            let tk_word_2 = stack_list.pop().unwrap().word;
            let right_number = BigDecimal::from_str(&tk_word_1).unwrap();
            let left_number  = BigDecimal::from_str(&tk_word_2).unwrap();
            match tk_item.token_type {
                TokenType::Plus => {
                    let val = &left_number + &right_number;
                    let precise_result = val.with_prec(30).normalized();
                    add_value(&mut stack_list, precise_result.to_string(), TokenType::Number, 0);
                },
                TokenType::Minus => {
                    let val = &left_number - &right_number;
                    let precise_result = val.with_prec(30).normalized();
                    add_value(&mut stack_list, precise_result.to_string(), TokenType::Number, 0);
                },
                TokenType::Multiply => {
                    let val = &left_number * &right_number;
                    let precise_result = val.with_prec(30).normalized();
                    add_value(&mut stack_list, precise_result.to_string(), TokenType::Number, 0);
                },
                TokenType::Divide => {
                    let val = &left_number / &right_number;
                    let precise_result = val.with_prec(30).normalized();
                    add_value(&mut stack_list, precise_result.to_string(), TokenType::Number, 0);
                },
                _ => {
                    panic!("calc error !");
                }
            }
        }
    }

    stack_list[0].word.clone()
}